package com.duoec.magichour.core.web.freemarker;

import com.duoec.magichour.core.CommonConst;
import com.duoec.magichour.core.web.freemarker.portlet.BasePortlet;
import freemarker.cache.FileTemplateLoader;
import freemarker.cache.MultiTemplateLoader;
import freemarker.cache.TemplateLoader;
import freemarker.core.Environment;
import freemarker.template.SimpleHash;
import freemarker.template.Template;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.lang.reflect.Field;
import java.util.Locale;
import java.util.Map;

/**
 * Created by ycoe on 16/4/29.
 */
public class XFreeMarkerView extends FreeMarkerView { //NOSONAR
    private static final Logger logger2 = LoggerFactory.getLogger(XFreeMarkerView.class);

    @Override
    protected void doRender(Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Long controllerStartTime = (Long) request.getAttribute(CommonConst.CONTROLLER_START_TIME);
        if (controllerStartTime != null) {
            long t = System.currentTimeMillis() - controllerStartTime;
            if (t > CommonConst.SLOW_CONTROLLER_TIME) {
                logger2.info("慢controller：{}ms", t);
            }
        }
        // Expose model to JSP tags (as request attributes).
        exposeModelAsRequestAttributes(model, request);
        // Expose all standard FreeMarker hash models.
        SimpleHash fmModel = buildTemplateModel(model, request, response);

        if (logger2.isDebugEnabled()) {
            logger2.debug("Rendering FreeMarker template [" + getUrl() + "] in FreeMarkerView '" + getBeanName() + "'");
        }
        // Grab the locale-specific version of the template.
        Locale locale = RequestContextUtils.getLocale(request);
        Template template = getTemplate(locale);

        if (FreemarkerResourceVars.VIEW_DIR == null) {
            hackGetViewDir(template);
        }
        Environment evn = template.createProcessingEnvironment(fmModel, response.getWriter(), null);

        FreemarkerResourceVars vars = new FreemarkerResourceVars(evn, template.getName());

        evn.setVariable(CommonConst.MAGIC_HOUR_VAR, vars);

        //尝试加载对应页面的js
        String name = template.getName();
        loadPageSource(vars, name);
        evn.process();
    }

    /**
     * 加载页面的默认样式和脚本
     *
     * @param vars
     * @param name
     */
    private void loadPageSource(FreemarkerResourceVars vars, String name) throws PortletException {
        String basePath = FreemarkerResourceVars.VIEW_DIR.getParentFile().getAbsolutePath();
        if (!name.startsWith("/")) {
            name = "/" + name;
        }
        String jsPath = name.replace(BasePortlet.TEMPLATE_SUFFIX, "js");
        File jsFile = new File(basePath + "/js" + jsPath);
        if (jsFile.exists()) {
            vars.addJs(jsFile, null);
        }

        String cssPath = name.replace(BasePortlet.TEMPLATE_SUFFIX, "css");
        File cssFile = new File(basePath + "/css" + cssPath);
        if (cssFile.exists()) {
            vars.addCss(cssFile, null);
        }
    }

    private static void hackGetViewDir(Template template) {
        MultiTemplateLoader templateLoader = ((MultiTemplateLoader) template.getConfiguration().getTemplateLoader());

        Field field = ReflectionUtils.findField(MultiTemplateLoader.class, "loaders");
        ReflectionUtils.makeAccessible(field);
        TemplateLoader[] loaders = (TemplateLoader[]) ReflectionUtils.getField(field, templateLoader);
        for (TemplateLoader loader : loaders) {
            if (loader instanceof FileTemplateLoader) {
                FileTemplateLoader fileTemplateLoader = (FileTemplateLoader) loader;
                FreemarkerResourceVars.VIEW_DIR = fileTemplateLoader.getBaseDirectory();
            }
        }
    }
}
